(function () {
  var IS_DONTENUM_BUGGY = (function () {
    for (var p in {
      toString: 1
    }) {
      if (p === "toString") {
        return false;
      }
    }
    return true;
  })();

  function keys(object) {
    var keys = [];
    for (var property in object) {
      keys.push(property);
    }
    return keys;
  }

  Object.keys = Object.keys || keys;

  function extend(destination, source) {
    for (var property in source) {
      destination[property] = source[property];
    }
    return destination;
  }

  extend(Function.prototype, (function () {
    var slice = Array.prototype.slice;

    function update(array, args) {
      var arrayLength = array.length, length = args.length;
      while (length--) {
        array[arrayLength + length] = args[length];
      }
      return array;
    }

    function merge(array, args) {
      array = slice.call(array, 0);
      return update(array, args);
    }

    function argumentNames() {
      var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1].replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, "")
        .replace(/\s+/g, "").split(",");
      return names.length == 1 && !names[0] ? [] : names;
    }

    function bind(context) {
      if (arguments.length < 2 && (typeof arguments[0] === "undefined")) {
        return this;
      }
      var __method = this, args = slice.call(arguments, 1);
      return function () {
        var a = merge(args, arguments);
        return __method.apply(context, a);
      };
    }

    function bindAsEventListener(context) {
      var __method = this, args = slice.call(arguments, 1);
      return function (event) {
        var a = update([event || window.event], args);
        return __method.apply(context, a);
      };
    }

    function curry() {
      if (!arguments.length) {
        return this;
      }
      var __method = this, args = slice.call(arguments, 0);
      return function () {
        var a = merge(args, arguments);
        return __method.apply(this, a);
      };
    }

    function delay(timeout) {
      var __method = this, args = slice.call(arguments, 1);
      timeout = timeout * 1000;
      return window.setTimeout(function () {
        return __method.apply(__method, args);
      }, timeout);
    }

    function defer() {
      var args = update([0.01], arguments);
      return this.delay.apply(this, args);
    }

    function wrap(wrapper) {
      var __method = this;
      return function () {
        var a = update([__method.bind(this)], arguments);
        return wrapper.apply(this, a);
      };
    }

    function methodize() {
      if (this._methodized) {
        return this._methodized;
      }
      var __method = this;
      return this._methodized = function () {
        var a = update([this], arguments);
        return __method.apply(null, a);
      };
    }

    return {
      argumentNames: argumentNames,
      bind: bind,
      bindAsEventListener: bindAsEventListener,
      curry: curry,
      delay: delay,
      defer: defer,
      wrap: wrap,
      methodize: methodize
    };
  })());
  var Class = null;
  Class = (function () {
    function subclass() {
    }

    function create() {
      var parent = null, properties = arguments;
      if (typeof (properties[0]) == "function") {
        // parent = properties.shift();
        parent = arguments[0]; // properties.shift();
        properties = [];
        for (var i = 1, length = arguments.length; i < length; i++) {
          properties.push(arguments[i]);
        }
      }

      function klass() {
        this.initialize.apply(this, arguments);
      }

      extend(klass, Class.Methods);
      klass.superclass = parent;
      klass.subclasses = [];
      if (parent) {
        subclass.prototype = parent.prototype;
        klass.prototype = new subclass;
        parent.subclasses.push(klass);
      }
      for (var i = 0, length = properties.length; i < length; i++) {
        klass.addMethods(properties[i]);
      }
      if (!klass.prototype.initialize) {
        klass.prototype.initialize = function () {
        };
      }
      klass.prototype.constructor = klass;
      return klass;
    }

    function addMethods(source) {
      var ancestor = this.superclass && this.superclass.prototype, properties = keys(source);
      if (IS_DONTENUM_BUGGY) {
        if (source.toString != Object.prototype.toString) {
          properties.push("toString");
        }
        if (source.valueOf != Object.prototype.valueOf) {
          properties.push("valueOf");
        }
      }
      for (var i = 0, length = properties.length; i < length; i++) {
        var property = properties[i], value = source[property];
        if (ancestor && (typeof (value) == "function") && value.argumentNames()[0] == "$super") {
          var method = value;
          value = (function (m) {
            return function () {
              return ancestor[m].apply(this, arguments);
            };
          })(property).wrap(method);
          value.valueOf = (function (method) {
            return function () {
              return method.valueOf.call(method);
            };
          })(method);
          value.toString = (function (method) {
            return function () {
              return method.toString.call(method);
            };
          })(method);
        }
        this.prototype[property] = value;
      }
      return this;
    }

    return {
      create: create,
      Methods: {
        addMethods: addMethods
      }
    };
  })();
  window.Class = Class;
})();
